﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ParallelInvoke
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        public void SetProgressBarValue(int index, int value)
        {

            ProgressBar pgb = null;
            switch (index)
            {
                case 1:
                    pgb = progressBar1;
                    break;
                case 2:
                    pgb = progressBar2;
                    break;
                case 3:
                    pgb = progressBar3;
                    break;
            }
            if (this.InvokeRequired)
            {
                Action<int> del = delegate(int argu)
                {
                    pgb.Value = argu;
                };
                this.BeginInvoke(del, value);
            }
            else
                pgb.Value = value;
        }

        private CountdownEvent threadCounter = new CountdownEvent(3);

        private CancellationTokenSource cts = null;

        private void EnableOrDisableButton(Button btn, bool Value)
        {
            Action del = delegate()
            {
                if (btn.Enabled != Value)
                    btn.Enabled = Value;
            };

            if (btn.InvokeRequired)
            {
                btn.Invoke(del);
            }
            else
                del();
        }

        private void DoWork(int index)
        {
            Random ran = new Random();
            for (int i = 0; i < 100; i++)
            {
                if (!cts.Token.IsCancellationRequested)
                {
                    Thread.Sleep(ran.Next(0, 500));
                    SetProgressBarValue(index, i);
                }
                else
                    throw new OperationCanceledException();
            }
            threadCounter.Signal();
            threadCounter.Wait();

            EnableOrDisableButton(btnStart, true);
            EnableOrDisableButton(btnCancel, false);

        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            threadCounter.Reset();

            cts = new CancellationTokenSource();

            ParallelOptions opt = new ParallelOptions();
            opt.CancellationToken = cts.Token;

            ThreadStart del = delegate()
            {
                try
                {
                    Parallel.Invoke(
                    opt,
                    () => DoWork(1),
                    () => DoWork(2),
                    () => DoWork(3)
                        );
                }
              
                catch (AggregateException exs)
                {
                    string ErrorMesage = "";
                    foreach (Exception ex in exs.InnerExceptions)
                    {
                        if (ex is OperationCanceledException)
                        {
                            EnableOrDisableButton(btnStart, true);
                            EnableOrDisableButton(btnCancel, false);
                            ErrorMesage = "操作被取消";
                            break;
                        }
                        else
                        {
                            ErrorMesage += "\n" + ex.Message;
                        }

                    }
                    MessageBox.Show(ErrorMesage);
                }

            };
            
                Thread th = new Thread(del);

                th.IsBackground = true;
                th.Start();
                EnableOrDisableButton(btnStart, false);
                EnableOrDisableButton(btnCancel, true);
            }
           


        

        private void btnCancel_Click(object sender, EventArgs e)
        {
            cts.Cancel();

        }
    }
}
